﻿namespace MicroCloud.Extensions
{
    public static partial class IServiceProviderExtensions
    {
        /// <summary>
        /// 开启一个事务处理
        /// </summary>
        /// <param name="rootProvider">信赖注入服务提供程序</param>
        /// <param name="action">要执行的业务委托</param>
        /// <param name="immediate">立即开启事务</param>
        /// <param name="isolationLevel">事务隔离级别</param>
        public static void BeginUnitOfWorkTransaction(this IServiceProvider rootProvider, Action<IServiceProvider> action,
            bool immediate = false, IsolationLevel? isolationLevel = null)
        {
            Check.NotNull(rootProvider, nameof(rootProvider));
            Check.NotNull(action, nameof(action));

            using IServiceScope scope = rootProvider.CreateScope();
            IServiceProvider scopeProvider = scope.ServiceProvider;

            IUnitOfWork unitOfWork = scopeProvider.GetUnitOfWork(true, immediate, isolationLevel);
            action(scopeProvider);
            unitOfWork.Commit();
        }

        /// <summary>
        /// 开启一个支持返回值的事务处理
        /// </summary>
        /// <typeparam name="TResult">返回类型</typeparam>
        /// <param name="rootProvider">信赖注入服务提供程序</param>
        /// <param name="func">要执行的方法函数</param>
        /// <param name="immediate">立即开启事务</param>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <returns>返回值</returns>
        public static TResult BeginUnitOfWorkTransaction<TResult>(this IServiceProvider rootProvider, Func<IServiceProvider, TResult> func,
            bool immediate = false, IsolationLevel? isolationLevel = null)
        {
            Check.NotNull(rootProvider, nameof(rootProvider));
            Check.NotNull(func, nameof(func));

            using IServiceScope scope = rootProvider.CreateScope();
            IServiceProvider scopeProvider = scope.ServiceProvider;

            IUnitOfWork unitOfWork = scopeProvider.GetUnitOfWork(true, immediate, isolationLevel);
            TResult result = func(scopeProvider);
            unitOfWork.Commit();

            return result;
        }

        /// <summary>
        /// 异步开启一个事务处理
        /// </summary>
        /// <param name="rootProvider">信赖注入服务提供程序</param>
        /// <param name="funcAsync">要执行的方法函数</param>
        /// <param name="immediate">立即开启事务</param>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <returns></returns>
        public static async Task BeginUnitOfWorkTransactionAsync(this IServiceProvider rootProvider, Func<IServiceProvider, Task> funcAsync,
            bool immediate = false, IsolationLevel? isolationLevel = null)
        {
            Check.NotNull(rootProvider, nameof(rootProvider));
            Check.NotNull(funcAsync, nameof(funcAsync));

            using IServiceScope scope = rootProvider.CreateScope();
            IServiceProvider scopeProvider = scope.ServiceProvider;

            IUnitOfWork unitOfWork = scopeProvider.GetUnitOfWork(true, immediate, isolationLevel);
            await funcAsync(scopeProvider);
            await unitOfWork.CommitAsync();
        }

        /// <summary>
        /// 异步开启一个支持返回值的事务处理
        /// </summary>
        /// <typeparam name="TResult">返回类型</typeparam>
        /// <param name="rootProvider">信赖注入服务提供程序</param>
        /// <param name="funcAsync">要执行的方法函数</param>
        /// <param name="immediate">立即开启事务</param>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <returns>返回值</returns>
        public static async Task<TResult> BeginUnitOfWorkTransactionAsync<TResult>(this IServiceProvider rootProvider, Func<IServiceProvider, Task<TResult>> funcAsync,
            bool immediate = false, IsolationLevel? isolationLevel = null)
        {
            Check.NotNull(rootProvider, nameof(rootProvider));
            Check.NotNull(funcAsync, nameof(funcAsync));

            using IServiceScope scope = rootProvider.CreateScope();
            IServiceProvider scopeProvider = scope.ServiceProvider;

            IUnitOfWork unitOfWork = scopeProvider.GetUnitOfWork(true, immediate, isolationLevel);
            TResult result = await funcAsync(scopeProvider);
            await unitOfWork.CommitAsync();

            return result;
        }

    }
}
